package cn.lyjuan.dwz_manage.core.java.filter;

import cn.lyjuan.dwz_manage.core.java.cst.DwzManageCst;
import cn.lyjuan.dwz_manage.core.java.util.SessUtils;
import cn.lyjuan.dwz_manage.core.java.util.SpringContextHolder;
import cn.lyjuan.dwz_manage.core.java.util.VerifyCodeUtil;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.util.StringUtils;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * Created by chad on 2016/8/23.
 * 由于加载顺序的原因，手动配置顺序
 */
//@WebFilter(filterName = "loginCodeFilter", urlPatterns = {"/login/*"},
//        initParams = {
//                @WebInitParam(name = "loginCodeUrl", value="/login/code"),
//                @WebInitParam(name = "loginProcessingUrl", value = "/login/submit"),
//                @WebInitParam(name = "failureUrl", value = "/login/login"),
//        })
public class LoginCodeFilter implements Filter
{
    private static Logger log = LogManager.getLogger(LoginCodeFilter.class.getName());

    /**
     * 该拦截器应该拦截的URL
     */
    public static final String FILTER_URL = "/login/*";

    /**
     * 获取图片验证码的URL
     */
    private static final String LOGIN_CODE_URL = "loginCodeUrl";

    /**
     * 登陆提交请求地址，对该地址进行拦截，判断验证码是否正确
     */
    private static final String LOGIN_PROCESSING_URL = "loginProcessingUrl";

    /**
     * 验证码错误，跳转页面
     */
    private static final String FAILURE_URL = "failureUrl";

    /**
     * 验证码提交参数名称
     */
    private static final String CODE_NAME = "codeName";

    /**
     * 验证码匹配错误会在HttpServletRequest中增加该名称值代表的属性值为true<br />
     * 如：req.setAttribute(name, true);
     */
    private static final String MISMATCH_CODE_NAME = "mismatchCode";

    /**
     * 放于Session中的验证码名称
     */
    private static final String SESS_OF_CODE = "P_SESS_OF_CODE_P";

    private String loginCodeUrl = "/login/code";
    private String loginProcessingUrl = "/login/submit";
    private String failureUrl = "/login/login";
    private String codeName            = "code";
    private String mismatchCodeName = "misamtchCode";

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException
    {
        HttpServletRequest  req  = (HttpServletRequest) servletRequest;
        HttpServletResponse resp = (HttpServletResponse) servletResponse;

        String servletPath = req.getServletPath();
        if (servletPath.startsWith(loginProcessingUrl))// 登陆提交
        {
            log.debug("dofilter loginProcessingUrl: {}", servletPath);
            String paramCode = req.getParameter(codeName);
            String sessCode  = SessUtils.get(req, String.class, SESS_OF_CODE, false);
            // session code 为空或不匹配
            if (StringUtils.isEmpty(sessCode) || !sessCode.equalsIgnoreCase(paramCode))
                redirectFailedUrl(req, resp);
            else
                filterChain.doFilter(servletRequest, servletResponse);
        } else if (servletPath.startsWith(loginCodeUrl))// 生成验证码
        {
            log.debug("dofilter general loginCodeImage: {}", servletPath);
            generateLoginCodeImage(req, resp);
        } else// 其他请求
        {
            filterChain.doFilter(servletRequest, servletResponse);
        }
    }


    @Override
    public void init(FilterConfig config) throws ServletException
    {
//        // 验证码图片
//        String loginCodeUrl = config.getInitParameter(LOGIN_CODE_URL);
//        if (StringUtils.isNull(loginCodeUrl))
//            throw new ServletException("do not have param: " + LOGIN_CODE_URL);
//        this.loginCodeUrl = loginCodeUrl;
//
//        // 登陆提交
//        String loginProcessingUrl = config.getInitParameter(LOGIN_PROCESSING_URL);
//        if (StringUtils.isNull(loginProcessingUrl))
//            throw new ServletException("do not have param: " + LOGIN_PROCESSING_URL);
//        this.loginProcessingUrl = loginProcessingUrl;
//
//        // 失败页面
//        String failureUrl = config.getInitParameter(FAILURE_URL);
//        if (StringUtils.isNull(failureUrl))
//            throw new ServletException("do not have param: " + FAILURE_URL);
//        this.failureUrl = failureUrl;
//
//        // 验证码名称
//        String codeName = config.getInitParameter(CODE_NAME);
//        if (!StringUtils.isNull(codeName))
//            this.codeName = codeName;
    }

    public static void setLog(Logger log)
    {
        LoginCodeFilter.log = log;
    }

    public void setLoginProcessingUrl(String loginProcessingUrl)
    {
        this.loginProcessingUrl = loginProcessingUrl;
    }

    public void setFailureUrl(String failureUrl)
    {
        this.failureUrl = failureUrl;
    }

    public void setCodeName(String codeName)
    {
        this.codeName = codeName;
    }

    private void generateLoginCodeImage(HttpServletRequest req, HttpServletResponse resp) throws IOException
    {
        setDisableCacheHeader(resp);

        //生成随机字串
        String verifyCode = VerifyCodeUtil.generateVerifyCode(4);

        SessUtils.save(req, SESS_OF_CODE, verifyCode.toLowerCase());

        //生成图片
        int w = 250, h = 100;
        VerifyCodeUtil.outputImage(w, h, resp.getOutputStream(), verifyCode);
    }

    private static DwzManageCst dwzManageCst;

    private void redirectFailedUrl(HttpServletRequest req, HttpServletResponse resp) throws IOException
    {
        log.debug("valid login code fail, redirect to failed url: " + this.failureUrl);
        if (null == dwzManageCst)
            dwzManageCst = SpringContextHolder.getBean(DwzManageCst.class);
        // 带错误标识
        String failureUrl = this.failureUrl + dwzManageCst.getHttpSuffix();
        failureUrl += "?" + mismatchCodeName + "=true";

        resp.sendRedirect(req.getContextPath() + failureUrl);
    }

    private void setDisableCacheHeader(HttpServletResponse resp)
    {
        // HTTP 1.0
        resp.setDateHeader("Expires", 1L);
        resp.addHeader("Pragma", "no-cache");
        // HTTP 1.1
        resp.setHeader("Cache-Control", "no-cache,no-store,max-age=0");
    }

    @Override
    public void destroy()
    {
    }
}
